package com.cjw.service.impl.livesquare;

import com.cjw.enums.share.DeleteRemark;
import com.cjw.enums.share.JoinType;
import com.cjw.enums.share.PlanState;
import com.cjw.enums.share.TagType;
import com.cjw.mapper.database.UserMapper;
import com.cjw.mapper.livesquare.PlanCardMapper;
import com.cjw.mapper.livesquare.PlanMapper;
import com.cjw.mapper.livesquare.UserPlanMapper;
import com.cjw.mapper.person.UserDetailMapper;
import com.cjw.mapper.soulread.TagMapper;
import com.cjw.pojo.assembler.PlanDTOAssembler;
import com.cjw.pojo.dto.database.PageDTO;
import com.cjw.pojo.dto.database.UserDTO;
import com.cjw.pojo.dto.livesquare.*;
import com.cjw.pojo.entity.database.User;
import com.cjw.pojo.entity.livesquare.Plan;
import com.cjw.pojo.entity.livesquare.PlanCard;
import com.cjw.pojo.entity.livesquare.UserPlan;
import com.cjw.pojo.entity.person.UserDetail;
import com.cjw.pojo.entity.soulread.Tag;
import com.cjw.pojo.query.livesquare.AddPlanDTO;
import com.cjw.service.livesquare.PlanService;
import com.cjw.service.soulread.TagService;
import com.cjw.util.BaseContextHolder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author : cjw
 * @date: : 2022/2/12 14:04
 * @description : PlanServiceImpl
 */
@Service("planService")
public class PlanServiceImpl implements PlanService {
    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private PlanMapper planMapper;

    @Autowired
    private UserPlanMapper userPlanMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserDetailMapper userDetailMapper;

    @Autowired
    private TagService tagService;

    @Autowired
    private PlanCardMapper planCardMapper;

    @Override
    public PageDTO<List<PlanSimpleDTO>> findAllPlans(Integer page, Integer size) {
        PageDTO<List<PlanSimpleDTO>> listPageDTO = new PageDTO<>();
        List<PlanSimpleDTO> planSimpleDTOS = new ArrayList<>();
        PageInfo<Plan> allPlans = getAllPlans(page, size);
        listPageDTO.setTotal((int) allPlans.getTotal());
        for (Plan plan : allPlans.getList()) {
            PlanSimpleDTO planSimpleDTO = new PlanSimpleDTO();
            planSimpleDTO.setId(plan.getId());
            planSimpleDTO.setContent(plan.getContent());
            planSimpleDTO.setTagName(tagMapper.selectByPrimaryKey(plan.getTagId()).getName());
            planSimpleDTO.setJoin(isJoin(plan.getId()));
            planSimpleDTO.setUserName(userMapper.selectByPrimaryKey(plan.getUserId()).getUserName());
            UserDetail userDetail = new UserDetail();
            userDetail.setUserId(plan.getUserId());
            planSimpleDTO.setUserHead(userDetailMapper.selectOne(userDetail).getHeadImage());
            planSimpleDTOS.add(planSimpleDTO);
        }
        listPageDTO.setDtos(planSimpleDTOS);
        return listPageDTO;
    }

    @Override
    public List<PlanSimpleDTO> findMaxListPlans(Integer number) {
        List<PlanSimpleDTO> planSimpleDTOS = new ArrayList<>();
        for (Long id : userPlanMapper.getMaxNumberPlanId(number)) {
            PlanSimpleDTO planSimpleDTO = new PlanSimpleDTO();
            planSimpleDTO.setId(id);
            planSimpleDTO.setContent(planMapper.selectByPrimaryKey(id).getContent());
            planSimpleDTOS.add(planSimpleDTO);
        }
        return planSimpleDTOS;
    }

    @Override
    public DetailPlanDTO findDetail(Long id) {
        /**
         * 查询的时候进行更新状态
         */
        updateState(id);
        DetailPlanDTO detailPlanDTO = new DetailPlanDTO();
        detailPlanDTO.setId(id);
        Plan planSelect = planMapper.selectByPrimaryKey(id);
        detailPlanDTO.setAddTime(planSelect.getAddTime());
        detailPlanDTO.setBeginTime(planSelect.getBegin_time());
        detailPlanDTO.setEndTime(planSelect.getEnd_time());
        detailPlanDTO.setContent(planSelect.getContent());
        if (!isJoin(id))
            detailPlanDTO.setJoin(JoinType.UNJOIN.getCode());
        else {
            if (!isClock(planSelect.getId(),planSelect.getDays(), new Date()))
                detailPlanDTO.setJoin(JoinType.CLOCKIN.getCode());
            else
                detailPlanDTO.setJoin(JoinType.UNCLOCK.getCode());
        }
        detailPlanDTO.setDays("("+planSelect.getDays()+")");
        detailPlanDTO.setState(planSelect.getState());
        detailPlanDTO.setUserName(userMapper.selectByPrimaryKey(planSelect.getUserId()).getUserName());
        UserDetail userDetail = new UserDetail();
        userDetail.setUserId(planSelect.getUserId());
        detailPlanDTO.setUserHeadImage(userDetailMapper.selectOne(userDetail).getHeadImage());
        UserPlan userPlan = new UserPlan();
        userPlan.setDeleteRemark(DeleteRemark.UNDELETE.getCode());
        userPlan.setPlanId(id);
        detailPlanDTO.setJoinNumber(userPlanMapper.selectCount(userPlan) + 1);
        return detailPlanDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePlan(Long id, Integer state) {
        Plan plan = new Plan();
        plan.setId(id);
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        if (state == 1) { // 取消参加计划
            if (planMapper.selectOne(plan).getUserId() == user.getId()) {
                // 创建者取消参与计划
                plan.setState(PlanState.CANCEL.getCode());
                return planMapper.updateByPrimaryKeySelective(plan) == 1;
            } else {
                // 非创建者取消参与计划
                Example example = new Example(UserPlan.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("user_id",user.getId());
                criteria.andEqualTo("plan_id",id);
                UserPlan userPlan = new UserPlan();
                userPlan.setDeleteRemark(DeleteRemark.DELETE.getCode());
                return userPlanMapper.updateByExampleSelective(userPlan,example) == 1;
            }
            // 在已参加情况先，无法参加
        } else if (isJoin(id) && state == 0) {
            return false;
            // 未参加，进行参加操作
        } else if(state == 0) {
            UserPlan userPlan = new UserPlan();
            userPlan.setPlanId(id);
            userPlan.setUserId(user.getId());
            userPlan.setAddTime(new Date());
            userPlan.setDeleteRemark(DeleteRemark.UNDELETE.getCode());
            return userPlanMapper.insert(userPlan) == 1;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeClock(Long planId, Integer type) {
        if (!isJoin(planId))
            return false;
        PlanCard planCard = new PlanCard();
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        planCard.setUserId(user.getId());
        planCard.setPlanId(planId);
        planCard.setAddTime(new Date());
        if (type == 0) { // 打卡
            if (!isClock(planId, planMapper.selectByPrimaryKey(planId).getDays(), new Date()))
                return false;
            return planCardMapper.insertSelective(planCard)==1;
        } else if (type == 1){ // 取消打卡
            if (planCardMapper.queryNowClockCount(planId, user.getId()) == 1)
                return planCardMapper.deleteNowClock(planCard)==1;
            else
                return false;
        }
        return true;
    }

    @Override
    public List<MyPlanDTO> getMyPlans(Date date) {
        ArrayList<MyPlanDTO> myPlanDTOS = new ArrayList<>();
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        for (Plan plan : userPlanMapper.getPlanByTime(user.getId(), date)) {
            if (isClock(plan.getId(), plan.getDays(), date)) {
                MyPlanDTO myPlanDTO = new MyPlanDTO();
                myPlanDTO.setContent(plan.getContent());
                myPlanDTO.setId(plan.getId());
                myPlanDTOS.add(myPlanDTO);
            }
        }
        return myPlanDTOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addPlan(AddPlanDTO addPlanDTO) {
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        Plan plan = PlanDTOAssembler.addDTOToEntity(addPlanDTO, user.getId(),
                tagService.addTag(addPlanDTO.getTagName(), TagType.INFO_LABEL.getMsg()));
        if (plan == null)
            return null;
        planMapper.insertUseGeneratedKeys(plan);
        return plan.getId();
    }

    @Override
    public Long matchPlan() {
        List<UserPlanCFDTO> userPlanCFDTOS = new ArrayList<>();
        UserDTO userDTO = (UserDTO) BaseContextHolder.get("user");
        // 录入模型
        for (User user : userMapper.selectAll()) {
            userPlanCFDTOS.add(new UserPlanCFDTO(user.getId(),
                    planCardMapper.queryPlanCardCount(user.getId())));
        }
        Recommend recommend = new Recommend();
        List<PlanCFDTO> planCFDTOS = recommend.recommend(userDTO.getId(), userPlanCFDTOS);
        return planCFDTOS != null ? planCFDTOS.get(0).getPlanId() : null;
    }

    /**
     * 判断当天是否可打卡
     * @param days
     * @return true 可打卡 false 不可打卡
     */
    private Boolean isClock(Long planId,String days,Date date) {
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        // 已打卡的，不能在打卡
        if (planCardMapper.queryNowClockCount(planId, user.getId()) == 1)
            return false;
        SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
        String week = sdf.format(date);
        for (String day : days.split(",")) {
            if (week.equals(day))
                return true;
        }
        return false;
    }

    /**
     * 分页获取计划
     * @param page
     * @param size
     * @return
     */
    private PageInfo<Plan> getAllPlans(Integer page, Integer size) {
        PageHelper.startPage(page,size);
        Example example = new Example(Plan.class);
        example.createCriteria().andEqualTo("state",0);
        example.setOrderByClause("id desc");
        return new PageInfo<>(planMapper.selectByExample(example));
    }

    /**
     * 判断是否有参与
     * @param planId
     * @return true 参与或计划结束 false 计划进行中并未参与
     */
    private Boolean isJoin(Long planId) {
        UserDTO user = (UserDTO) BaseContextHolder.get("user");
        Plan plan = new Plan();
        plan.setId(planId);
        plan.setState(PlanState.ONGOING.getCode());
        Plan plan1 = planMapper.selectOne(plan);
        if (plan1 == null || plan1.getEnd_time().compareTo(new Date()) == -1) {
            updateState(planId);
            return true;
        }
        if (plan1.getUserId() == user.getId()) // 发布人默认参与计划
            return true;
        UserPlan userPlan = new UserPlan();
        userPlan.setPlanId(planId);
        userPlan.setUserId(user.getId());
        userPlan.setDeleteRemark(DeleteRemark.UNDELETE.getCode());
        return userPlanMapper.selectCount(userPlan) == 1;
    }

    /**
     * 更新计划状态 - 超过end_time的设置为结束
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    void updateState(Long id) {
        Plan plan = new Plan();
        plan.setId(id);
        plan.setState(0);
        Plan planSelect = planMapper.selectOne(plan);
        if (planSelect != null) {
            if (planSelect.getEnd_time().compareTo(new Date()) == -1) {
                plan.setState(PlanState.FINISH.getCode());
                planMapper.updateByPrimaryKeySelective(plan);
            }
        }
    }
}
